<?php 

    /**
     * This file is part of the Intelligencer package.
     * For the full copyright and license, please view the LICENSE
     * file that was distributed with this source code.
     * 
     * @author         Roman Drapeko <roman.drapeko@gmail.com>
     * @copyright      Roman Drapeko <roman.drapeko@gmail.com>, 2009 - present
     */

    /**
     * This class contains different useful functions
     * @author drapeko
     */
    class itUtil {
        
        const DEFAULT_NAMESPACE = 'namespace';
        const CLASSES = 'classes';
        const INTERFACES = 'interfaces';

        /**
         * Returns whether the value is in array. It differences from in_array function in a way it checks. It uses "===" instead of "==".
         * 
         * @param mixed $obj
         * @param array $array
         * @return boolean
         */
        public static function inArray($obj, $array) {
            foreach($array as $a) {
                if ($a === $obj) {
                    return true;
                }
            }
            
            return false;
        }
        
        /**
         * Returns an array of the namespace and class. Namespace is the first element. Class is the second element.
         * If class does not have namespace null is returned. Below possible incoming parameters are presented:
         * <code>
         * array('namespace', 'class') 
         * array('class')
         * 'class'
         * 'namespace\class'
         * </code>
         * 
         * @param string $className
         * @param boolean $throwExceptionIfBothEmpty false
         * @return array
         */
        public static function getClassAndNS($className, $throwExceptionIfBothEmpty = false) {
            $result = array(0 => null, 1 => null);
            
            if (is_array($className)) {
                $inSize = count($className);
                if ($inSize >= 2) {
                    $result[0] = $className[0];
                    $result[1] = $className[1];
                } else if ($inSize == 1) {
                    $result[1] = $className[0];
                }
            } else {
                $result[1] = $className;
                $pos = strrpos($className, '\\');
                if ($pos !== false) {
                    $result[0] = substr($className, 0, $pos);
                    $result[1] = substr($className, $pos + 1);
                }
            }
            
            if ($throwExceptionIfBothEmpty) {
                if ($namespace == null && $class == null) {
                    throw new itInvalidParameterException('namespace and class are both empty');
                }
            }
            
            return $result;
        }
        
        /**
         * The same as {@link getClassAndNS} but returns the classname and namespace in lowercase
         * @param string $className
         * @param boolean $throwExceptionIfBothEmpty false
         * @return array
         */
        public static function getLowerClassAndNS($className, $throwExceptionIfBothEmpty = false) {
            $arr = self::getClassAndNS($className, $throwExceptionIfBothEmpty);
            $result = array(0 => strtolower($arr[0]), 1 => strtolower($arr[1]));
            return $result;
        }
        
        /**
         * removes slashes from both sides
         * @param string $path
         * @return string
         */
        public static function trimSlashes($path) {
            return preg_replace(array("/^\//", "/\/$/", "/^\\\\/", "/\\\\$/"), '', $path);
        }
        
        /**
         * substract one array from another
         * @param array $arrayA
         * @param array $arrayB
         * @return array 
         */
        public static function minusArrays($arrayA, $arrayB) {
            return array_intersect(array_diff($arrayA, $arrayB), $arrayA);
        }
        
        /**
         * Case-insensitive check whether element in array
         * @param string $needle
         * @param string $haystack
         * @return boolean
         */
        public static function inArrayInsensitive($needle, $haystack) {
            return in_array(strtolower($needle), array_map('strtolower', $haystack));
        }
        
        /**
         * Cartesian product of the arrays
         * @param $arrays
         * @return cartesian product of the arrays
         */
        public static function arrayCartesian($arrays) {
           $result = array();
           $size = (count($arrays) > 0) ? 1 : 0;
           $arraysSize = count($arrays);
           
           foreach($arrays as $array) {
               $size = $size * count($array);
           }
           
           $curr = 0;
           for ($i = 0; $i < $size; $i++) {
               $result[$i] = array();
               
               for ($j = 0; $j < $arraysSize; $j++) {
                   $current = current($arrays[$j]);
                   array_push($result[$i], $current);
               }
               
               for ($j = $arraysSize - 1; $j >= 0; $j--) {
                   if(next($arrays[$j])) {
                       break;
                   } else {
                       reset($arrays[$j]);
                   }
               }
           }
           
           return $result;
        }
        
        /**
         * Cartesian product of the arrays persisting the keys
         * @param $arrays
         * @return cartesian product of the arrays
         */
        public static function arrayCartesianKeys($arrays) {
            $keys = array_keys($arrays);
            $arrays = array_values($arrays);
            
            $result = array();
            $size = (count($arrays) > 0) ? 1 : 0;
            $arraysSize = count($arrays);
            
            foreach($arrays as $array) {
               $size = $size * count($array);
            }
            
            $curr = 0;
            for ($i = 0; $i < $size; $i++) {
               $result[$i] = array();
               
               for ($j = 0; $j < $arraysSize; $j++) {
                   $current = current($arrays[$j]);
                   $result[$i][$keys[count($result[$i])]] = $current;
               }
               
               for ($j = $arraysSize - 1; $j >= 0; $j--) {
                   if(next($arrays[$j])) {
                       break;
                   } else {
                       reset($arrays[$j]);
                   }
               }
            }
            
            return $result;
        }
        
        /**
         * Returns the real path. If this is a phar location will return the correct results.
         * 
         * @param string $inPath
         * @return string
         */
        public static function getRealPath($inPath) {
            if (is_readable($inPath)) {
                $realPath = realpath($inPath);
                
                if ($realPath != null) {
                    return $realPath;
                }
                
                // try to identify whether this is a phar
                preg_match('/(phar:\/\/)(.*\.phar)(.*)/', $inPath, $pharMatches);
                if (!empty($pharMatches) && ($path = realpath($pharMatches[2]))) {
                    return $pharMatches[1].$path.str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $pharMatches[3]);
                }
            }
            return null;
        }
        
        /**
         * Unlinks the file if it exists
         * @param string $path
         * @return void
         */
        public static function unlink($path) {
            if (is_file($path) && is_readable($path)) {
                unlink($path);
            }
        }
        
        /**
         * Recursively deletes the particular directory
         * @param string $dir path to the directory
         * @return void
         */
        public static function deleteDir($dir) {
            if (!file_exists($dir)) return true;
            if (!is_dir($dir)) return unlink($dir);
            foreach (scandir($dir) as $item) {
                if ($item == '.' || $item == '..') continue;
                if (!self::deleteDir($dir.DIRECTORY_SEPARATOR.$item)) return false;
            }
            return rmdir($dir);
        }
        
        /**
         * Recursively copies the particular directory
         * @param   string  $src
         * @param   string  $dest
         * @return  void
         */
        public static function copyDirectory($src, $dst) {
            $dir = opendir($src);
            @mkdir($dst);
            while(false !== ( $file = readdir($dir)) ) {
                if (( $file != '.' ) && ( $file != '..' ) && !preg_match("/^.*\.svn$/", $file)) {
                    if ( is_dir($src . '/' . $file) ) {
                        copyDirectory($src . '/' . $file,$dst . '/' . $file);
                    }
                    else {
                        copy($src . '/' . $file,$dst . '/' . $file);
                    }
                }
            }
            closedir($dir);
        }
        
    }
    
    
?>